{
  "cells": [
    {
      "cell_type": "markdown",
      "id": "f2195672-0cab-4967-ba8a-c6544635547d",
      "metadata": {},
      "source": [
        "# How to handle cases where no queries are generated\n",
        "\n",
        ":::info Prerequisites\n",
        "\n",
        "This guide assumes familiarity with the following:\n",
        "\n",
        "- [Query analysis](/docs/tutorials/query_analysis)\n",
        "\n",
        ":::\n",
        "\n",
        "Sometimes, a query analysis technique may allow for any number of queries to be generated - including no queries! In this case, our overall chain will need to inspect the result of the query analysis before deciding whether to call the retriever or not.\n",
        "\n",
        "We will use mock data for this example."
      ]
    },
    {
      "cell_type": "markdown",
      "id": "a4079b57-4369-49c9-b2ad-c809b5408d7e",
      "metadata": {},
      "source": [
        "## Setup\n",
        "\n",
        "### Install dependencies\n",
        "\n",
        "```{=mdx}\n",
        "import IntegrationInstallTooltip from \"@mdx_components/integration_install_tooltip.mdx\";\n",
        "import Npm2Yarn from \"@theme/Npm2Yarn\";\n",
        "\n",
        "<IntegrationInstallTooltip></IntegrationInstallTooltip>\n",
        "\n",
        "<Npm2Yarn>\n",
        "  @langchain/community @langchain/openai zod chromadb\n",
        "</Npm2Yarn>\n",
        "```\n",
        "\n",
        "### Set environment variables\n",
        "\n",
        "```\n",
        "OPENAI_API_KEY=your-api-key\n",
        "\n",
        "# Optional, use LangSmith for best-in-class observability\n",
        "LANGSMITH_API_KEY=your-api-key\n",
        "LANGCHAIN_TRACING_V2=true\n",
        "```"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "c20b48b8-16d7-4089-bc17-f2d240b3935a",
      "metadata": {},
      "source": [
        "### Create Index\n",
        "\n",
        "We will create a vectorstore over fake information."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "id": "1f621694",
      "metadata": {},
      "outputs": [],
      "source": [
        "import { Chroma } from \"@langchain/community/vectorstores/chroma\"\n",
        "import { OpenAIEmbeddings } from \"@langchain/openai\"\n",
        "import \"chromadb\";\n",
        "\n",
        "const texts = [\"Harrison worked at Kensho\"]\n",
        "const embeddings = new OpenAIEmbeddings({ model: \"text-embedding-3-small\" })\n",
        "const vectorstore = await Chroma.fromTexts(texts, {}, embeddings, {\n",
        "  collectionName: \"harrison\"\n",
        "})\n",
        "const retriever = vectorstore.asRetriever(1);"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "57396e23-c192-4d97-846b-5eacea4d6b8d",
      "metadata": {},
      "source": [
        "## Query analysis\n",
        "\n",
        "We will use function calling to structure the output. However, we will configure the LLM such that is doesn't NEED to call the function representing a search query (should it decide not to). We will also then use a prompt to do query analysis that explicitly lays when it should and shouldn't make a search."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 24,
      "id": "0b51dd76-820d-41a4-98c8-893f6fe0d1ea",
      "metadata": {},
      "outputs": [],
      "source": [
        "import { z } from \"zod\";\n",
        "\n",
        "const searchSchema = z.object({\n",
        "    query: z.string().describe(\"Similarity search query applied to job record.\"),\n",
        "});"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "b7916d00",
      "metadata": {},
      "source": [
        "```{=mdx}\n",
        "import ChatModelTabs from \"@theme/ChatModelTabs\";\n",
        "\n",
        "<ChatModelTabs customVarName=\"llm\" />\n",
        "```"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 25,
      "id": "783c03c3-8c72-4f88-9cf4-5829ce6745d6",
      "metadata": {},
      "outputs": [],
      "source": [
        "import { zodToJsonSchema } from \"zod-to-json-schema\";\n",
        "import { ChatPromptTemplate } from \"@langchain/core/prompts\";\n",
        "import { RunnableSequence, RunnablePassthrough } from \"@langchain/core/runnables\";\n",
        "\n",
        "const system = `You have the ability to issue search queries to get information to help answer user information.\n",
        "\n",
        "You do not NEED to look things up. If you don't need to, then just respond normally.`;\n",
        "const prompt = ChatPromptTemplate.fromMessages(\n",
        "  [\n",
        "    [\"system\", system],\n",
        "    [\"human\", \"{question}\"],\n",
        "  ]\n",
        ")\n",
        "const llmWithTools = llm.bind({\n",
        "  tools: [{\n",
        "    type: \"function\" as const,\n",
        "    function: {\n",
        "      name: \"search\",\n",
        "      description: \"Search over a database of job records.\",\n",
        "      parameters: zodToJsonSchema(searchSchema),\n",
        "    }\n",
        "  }]\n",
        "})\n",
        "const queryAnalyzer = RunnableSequence.from([\n",
        "  {\n",
        "    question: new RunnablePassthrough(),\n",
        "  },\n",
        "  prompt,\n",
        "  llmWithTools\n",
        "])"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "b9564078",
      "metadata": {},
      "source": [
        "We can see that by invoking this we get an message that sometimes - but not always - returns a tool call."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 26,
      "id": "bc1d3863",
      "metadata": {},
      "outputs": [
        {
          "data": {
            "text/plain": [
              "AIMessage {\n",
              "  lc_serializable: \u001b[33mtrue\u001b[39m,\n",
              "  lc_kwargs: {\n",
              "    content: \u001b[32m\"\"\u001b[39m,\n",
              "    additional_kwargs: {\n",
              "      function_call: \u001b[90mundefined\u001b[39m,\n",
              "      tool_calls: [\n",
              "        {\n",
              "          id: \u001b[32m\"call_uqHm5OMbXBkmqDr7Xzj8EMmd\"\u001b[39m,\n",
              "          type: \u001b[32m\"function\"\u001b[39m,\n",
              "          function: \u001b[36m[Object]\u001b[39m\n",
              "        }\n",
              "      ]\n",
              "    }\n",
              "  },\n",
              "  lc_namespace: [ \u001b[32m\"langchain_core\"\u001b[39m, \u001b[32m\"messages\"\u001b[39m ],\n",
              "  content: \u001b[32m\"\"\u001b[39m,\n",
              "  name: \u001b[90mundefined\u001b[39m,\n",
              "  additional_kwargs: {\n",
              "    function_call: \u001b[90mundefined\u001b[39m,\n",
              "    tool_calls: [\n",
              "      {\n",
              "        id: \u001b[32m\"call_uqHm5OMbXBkmqDr7Xzj8EMmd\"\u001b[39m,\n",
              "        type: \u001b[32m\"function\"\u001b[39m,\n",
              "        function: { name: \u001b[32m\"search\"\u001b[39m, arguments: \u001b[32m'{\"query\":\"Harrison\"}'\u001b[39m }\n",
              "      }\n",
              "    ]\n",
              "  }\n",
              "}"
            ]
          },
          "execution_count": 26,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "await queryAnalyzer.invoke(\"where did Harrison work\")"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 27,
      "id": "af62af17-4f90-4dbd-a8b4-dfff51f1db95",
      "metadata": {},
      "outputs": [
        {
          "data": {
            "text/plain": [
              "AIMessage {\n",
              "  lc_serializable: \u001b[33mtrue\u001b[39m,\n",
              "  lc_kwargs: {\n",
              "    content: \u001b[32m\"Hello! How can I assist you today?\"\u001b[39m,\n",
              "    additional_kwargs: { function_call: \u001b[90mundefined\u001b[39m, tool_calls: \u001b[90mundefined\u001b[39m }\n",
              "  },\n",
              "  lc_namespace: [ \u001b[32m\"langchain_core\"\u001b[39m, \u001b[32m\"messages\"\u001b[39m ],\n",
              "  content: \u001b[32m\"Hello! How can I assist you today?\"\u001b[39m,\n",
              "  name: \u001b[90mundefined\u001b[39m,\n",
              "  additional_kwargs: { function_call: \u001b[90mundefined\u001b[39m, tool_calls: \u001b[90mundefined\u001b[39m }\n",
              "}"
            ]
          },
          "execution_count": 27,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "await queryAnalyzer.invoke(\"hi!\")"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "c7c65b2f-7881-45fc-a47b-a4eaaf48245f",
      "metadata": {},
      "source": [
        "## Retrieval with query analysis\n",
        "\n",
        "So how would we include this in a chain? Let's look at an example below."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 33,
      "id": "b209e10e",
      "metadata": {},
      "outputs": [],
      "source": [
        "import { JsonOutputKeyToolsParser } from \"@langchain/core/output_parsers/openai_tools\";\n",
        "\n",
        "const outputParser = new JsonOutputKeyToolsParser({\n",
        "  keyName: \"search\",\n",
        "})"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 46,
      "id": "8dac7866",
      "metadata": {},
      "outputs": [],
      "source": [
        "import { RunnableConfig, RunnableLambda } from \"@langchain/core/runnables\";\n",
        "\n",
        "const chain = async (question: string, config?: RunnableConfig) => {\n",
        "  const response = await queryAnalyzer.invoke(question, config);\n",
        "  if (\"tool_calls\" in response.additional_kwargs && response.additional_kwargs.tool_calls !== undefined) {\n",
        "    const query = await outputParser.invoke(response, config);\n",
        "    return retriever.invoke(query[0].query, config);\n",
        "  } else {\n",
        "    return response;\n",
        "  }\n",
        "}\n",
        "\n",
        "const customChain = new RunnableLambda({ func: chain });"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 47,
      "id": "232ad8a7-7990-4066-9228-d35a555f7293",
      "metadata": {},
      "outputs": [
        {
          "data": {
            "text/plain": [
              "[ Document { pageContent: \u001b[32m\"Harrison worked at Kensho\"\u001b[39m, metadata: {} } ]"
            ]
          },
          "execution_count": 47,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "await customChain.invoke(\"where did Harrison Work\")"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 48,
      "id": "28e14ba5",
      "metadata": {},
      "outputs": [
        {
          "data": {
            "text/plain": [
              "AIMessage {\n",
              "  lc_serializable: \u001b[33mtrue\u001b[39m,\n",
              "  lc_kwargs: {\n",
              "    content: \u001b[32m\"Hello! How can I assist you today?\"\u001b[39m,\n",
              "    additional_kwargs: { function_call: \u001b[90mundefined\u001b[39m, tool_calls: \u001b[90mundefined\u001b[39m }\n",
              "  },\n",
              "  lc_namespace: [ \u001b[32m\"langchain_core\"\u001b[39m, \u001b[32m\"messages\"\u001b[39m ],\n",
              "  content: \u001b[32m\"Hello! How can I assist you today?\"\u001b[39m,\n",
              "  name: \u001b[90mundefined\u001b[39m,\n",
              "  additional_kwargs: { function_call: \u001b[90mundefined\u001b[39m, tool_calls: \u001b[90mundefined\u001b[39m }\n",
              "}"
            ]
          },
          "execution_count": 48,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "await customChain.invoke(\"hi!\")"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "666100c5",
      "metadata": {},
      "source": [
        "## Next steps\n",
        "\n",
        "You've now learned some techniques for handling irrelevant questions in query analysis systems.\n",
        "\n",
        "Next, check out some of the other query analysis guides in this section, like [how to use few-shot examples](/docs/how_to/query_few_shot)."
      ]
    }
  ],
  "metadata": {
    "kernelspec": {
      "display_name": "Deno",
      "language": "typescript",
      "name": "deno"
    },
    "language_info": {
      "file_extension": ".ts",
      "mimetype": "text/x.typescript",
      "name": "typescript",
      "nb_converter": "script",
      "pygments_lexer": "typescript",
      "version": "5.3.3"
    }
  },
  "nbformat": 4,
  "nbformat_minor": 5
}
